Skip to content

demos: introduce DevModule + rename bin/app.php to bin/be.php - #19

Merged
koriym merged 2 commits into
1.xfrom
demos-dev-module
Apr 20, 2026
Merged

koriym merged 2 commits into
1.xfrom
demos-dev-module

Conversation

@koriym

@koriym koriym commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Rename bin/app.php → bin/be.php across all demos (aligns with skeleton's universal entry convention).
  • Introduce per-demo DevModule that installs AppModule and rebinds BecomingInterface to DevBecoming plus a SemanticLoggerInterface provider — mirrors the skeleton's dev/app module split.
  • Add DevBecoming wrapper per demo: writes var/log/<demo>.json from a finally block so failed pipelines are captured too.
  • Commit sample transcripts (var/log/<demo>.json) as reference outputs readers can inspect alongside the code.

Test plan

  • cd demos/hello-world && composer install && php bin/be.php produces expected output and log
  • Same for medical-triage, user-registration, order-processing
  • vendor/bin/stree var/log/<demo>.json renders each transcript

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added demonstration applications for hello-world, medical-triage, order-processing, and user-registration patterns
    • Semantic logging now captures execution flow and application state transitions
    • Generated JSON logs provide detailed operational visibility of application behavior
  • Documentation

    • Demo applications serve as practical usage examples for the framework

Each runnable demo (hello-world, medical-triage, user-registration,
order-processing) now wraps Becoming with a per-demo DevBecoming that
flushes the semantic log to var/log/<demo>.json in a finally block, so
failed runs are captured too. The dev-specific bindings are isolated
in DevModule (AppModule stays focused on the demo's own bindings).

A generated var/log/<demo>.json is checked in alongside each demo as
a reference transcript, readable without running the code.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@koriym has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 46 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 46 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd617459-c401-4c21-817d-07e4d60b22c4

📥 Commits

Reviewing files that changed from the base of the PR and between c640481 and cf6e604.

📒 Files selected for processing (8)
  • demos/hello-world/src/Becoming/DevBecoming.php
  • demos/hello-world/var/log/hello-world.json
  • demos/medical-triage/src/Becoming/DevBecoming.php
  • demos/medical-triage/var/log/medical-triage.json
  • demos/order-processing/src/Becoming/DevBecoming.php
  • demos/order-processing/var/log/order-processing.json
  • demos/user-registration/src/Becoming/DevBecoming.php
  • demos/user-registration/var/log/user-registration.json
📝 Walkthrough

Walkthrough

The PR adds development environment infrastructure across demo projects by introducing DevModule dependency injection configurations, DevBecoming wrapper classes for semantic logging, and DevSemanticLoggerProvider providers. Executable be.php scripts and JSON log files are added to each demo to enable structured logging and CLI output.

Changes

Cohort / File(s) Summary
Hello-world Demo
demos/hello-world/bin/be.php, demos/hello-world/src/Becoming/DevBecoming.php, demos/hello-world/src/Module/DevModule.php, demos/hello-world/src/Module/DevSemanticLoggerProvider.php, demos/hello-world/var/log/hello-world.json, demos/hello-world/src/Module/AppModule.php
Added executable script with Ray DI injector setup. Introduced DevBecoming wrapper class that delegates to wrapped callable and logs semantic events to JSON in a finally block. Created DevModule configuring DI bindings and DevSemanticLoggerProvider for singleton logger management. Generated semantic log artifact. Reordered import statement in AppModule.
Medical-triage Demo
demos/medical-triage/bin/be.php, demos/medical-triage/src/Becoming/DevBecoming.php, demos/medical-triage/src/Module/DevModule.php, demos/medical-triage/src/Module/DevSemanticLoggerProvider.php, demos/medical-triage/var/log/medical-triage.json
Added executable script with DI-based BecomingInterface resolution. Implemented DevBecoming decorator pattern with guaranteed logging in finally block. Created DevModule with singleton-scoped semantic logger provider. Generated semantic log artifact capturing patient triage workflow events.
Order-processing Demo
demos/order-processing/bin/be.php, demos/order-processing/src/Becoming/DevBecoming.php, demos/order-processing/src/Module/DevModule.php, demos/order-processing/src/Module/DevSemanticLoggerProvider.php, demos/order-processing/var/log/order-processing.json
Refactored script from direct instantiation to DI-based lookup. Added DevBecoming with post-execution logging via finally block. Introduced DevModule with semantic logger binding configuration. Generated comprehensive order workflow semantic log artifact.
User-registration Demo
demos/user-registration/bin/be.php, demos/user-registration/src/Becoming/DevBecoming.php, demos/user-registration/src/Module/DevModule.php, demos/user-registration/src/Module/DevSemanticLoggerProvider.php, demos/user-registration/var/log/user-registration.json, demos/user-registration/src/Module/AppModule.php
Added executable script invoking DI-resolved BecomingInterface. Implemented DevBecoming decorator with semantic event logging persistence. Created DevModule configuring Ray DI container and singleton logger scope. Generated nested semantic log documenting registration flow stages and user creation events. Repositioned import statement in AppModule.

Sequence Diagram

sequenceDiagram
    actor Script as bin/be.php
    participant Injector as Ray\\Di\\Injector
    participant DevModule as DevModule
    participant DevBecoming as DevBecoming
    participant Becoming as Becoming<br/>(Wrapped)
    participant Logger as SemanticLogger
    participant FileSystem as var/log/

    Script->>Injector: new Injector(DevModule)
    Injector->>DevModule: configure()
    DevModule->>Injector: Install AppModule & bind interfaces
    DevModule->>Injector: Bind SemanticLoggerInterface via Provider
    
    Script->>Injector: getInstance(BecomingInterface)
    Injector->>DevBecoming: new (wrapped, logger)
    Injector-->>Script: DevBecoming instance
    
    Script->>DevBecoming: __invoke(input)
    activate DevBecoming
    DevBecoming->>Becoming: __invoke(input)
    activate Becoming
    Becoming-->>DevBecoming: result (object)
    deactivate Becoming
    
    Note over DevBecoming: finally block executes<br/>regardless of success/failure
    DevBecoming->>Logger: flush()
    Logger-->>DevBecoming: events array
    DevBecoming->>DevBecoming: json_encode(events)
    DevBecoming->>FileSystem: file_put_contents(*.json)
    deactivate DevBecoming
    
    DevBecoming-->>Script: result
    Script-->>Script: assert & print output
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰✨ A rabbit's celebration of logs well-kept:

Four demos now with methods bright,
DevBecoming wraps the logic tight,
Semantic logs in JSON's grace,
Dependency injection's rightful place,
Finally blocks ensure all's right! 📝🎯

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: introducing DevModule for development-specific dependency injection across demos, and renaming the entry script from bin/app.php to bin/be.php.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch demos-dev-module

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
demos/user-registration/src/Becoming/DevBecoming.php (2)

30-46: Exception raised inside finally would mask the original Becoming failure.

If writing the log throws (e.g., disk full, permissions, json_encode returning false with JSON_THROW_ON_ERROR-like semantics indirectly via a later call), that exception replaces any exception propagating from ($this->becoming)($input), hiding the real pipeline failure from the developer running the demo. For a dev-only tool this is acceptable, but wrapping the persistence in its own try/catch (logging to stderr instead of throwing) would keep the observed failure signal intact.

♻️ Optional hardening
         try {
             return ($this->becoming)($input);
         } finally {
-            $dir = dirname(__DIR__, 2) . '/var/log';
-            if (! is_dir($dir)) {
-                mkdir($dir, 0755, true);
-            }
-
-            file_put_contents(
-                $dir . '/user-registration.json',
-                json_encode($this->logger->flush(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
-            );
+            try {
+                $dir = dirname(__DIR__, 2) . '/var/log';
+                if (! is_dir($dir)) {
+                    mkdir($dir, 0755, true);
+                }
+
+                $json = json_encode(
+                    $this->logger->flush(),
+                    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
+                );
+                if ($json !== false) {
+                    file_put_contents($dir . '/user-registration.json', $json);
+                }
+            } catch (\Throwable $e) {
+                fwrite(STDERR, "DevBecoming log write failed: {$e->getMessage()}\n");
+            }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@demos/user-registration/src/Becoming/DevBecoming.php` around lines 30 - 46,
The finally block in DevBecoming::__invoke currently writes logs and can throw,
which would mask exceptions from ($this->becoming)($input); wrap the entire
persistence sequence (the dirname/ mkdir check, json_encode of
$this->logger->flush(), and file_put_contents) in its own try/catch inside the
finally so any errors are caught and do not propagate; on catch write a concise
error to STDERR (e.g., via fwrite(STDERR, ...)) and do not rethrow; additionally
validate json_encode succeeded (or use JSON_THROW_ON_ERROR inside that try)
before calling file_put_contents to avoid silent false results from
$this->logger->flush().

22-47: Heads-up: near-identical DevBecoming will land in each demo.

This class is structurally the same across the four demos, differing only in the JSON filename (user-registration.json, hello-world.json, etc.). That’s consistent with the PR’s “per-demo DevModule” philosophy, and the filename-by-demo is the only real variation — so a shared base class probably isn’t worth it. Flagging only so future maintainers know any bug fix here (e.g., the finally concern above) needs to be replicated in the other three DevBecoming files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@demos/user-registration/src/Becoming/DevBecoming.php` around lines 22 - 47,
DevBecoming's __invoke finally block is duplicated across demos with only the
output filename differing (e.g., user-registration.json vs hello-world.json);
when you fix the finally behavior (e.g., ensure logger->flush() errors are
handled, directory creation permissions, or atomic file write), apply the same
change to the other DevBecoming classes so all demos stay consistent—locate the
DevBecoming class and its __invoke method and update the file write logic
(logger->flush(), dirname(...)/var/log creation, and file_put_contents call) and
replicate the identical fix to the other three DevBecoming files, preserving
each demo's distinct JSON filename.
demos/medical-triage/bin/be.php (1)

22-27: Consider asserting the final type for parity with other demos.

The sibling entrypoints (hello-world, user-registration, order-processing) all do assert($final instanceof <FinalClass>) before using the result. This script only prints $final::class, so if the pipeline ever returns an unexpected object the demo silently accepts it. Adding a matching assert keeps the demos consistent and documents the expected outcome.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@demos/medical-triage/bin/be.php` around lines 22 - 27, Add an instanceof
assertion to verify the pipeline output ($final) matches the expected final
class before using it: locate the code that calls $becoming(new
PatientInput(...)) and immediately after the result is produced (before or after
the printf) add an assertion like assert($final instanceof <ExpectedFinalClass>)
— replace <ExpectedFinalClass> with the actual final type returned by the triage
pipeline (e.g., TriageResult) to match the other demos' pattern and document the
expected outcome.
demos/user-registration/bin/be.php (1)

33-33: Relative vendor/bin/stree path couples script to CWD.

passthru('vendor/bin/stree ' . ...) only resolves when invoked from the demo directory (as documented in the PR test plan). Running php demos/user-registration/bin/be.php from the repo root will fail to locate stree even though the script otherwise works via dirname(__DIR__) for autoload. Consider resolving the binary path relative to the script, mirroring how vendor/autoload.php is resolved.

♻️ Proposed fix
-passthru('vendor/bin/stree ' . escapeshellarg(dirname(__DIR__) . '/var/log/user-registration.json'));
+passthru(
+    escapeshellarg(dirname(__DIR__) . '/vendor/bin/stree') . ' '
+    . escapeshellarg(dirname(__DIR__) . '/var/log/user-registration.json'),
+);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@demos/user-registration/bin/be.php` at line 33, The passthru call uses a
relative 'vendor/bin/stree' which breaks when the script is run from a different
CWD; change the command to build the binary path relative to the script
directory (use dirname(__DIR__, 3) to reach the repo root from
demos/user-registration/bin), e.g. compute the full path to vendor/bin/stree via
dirname(__DIR__, 3) . '/vendor/bin/stree', wrap it with escapeshellarg as
before, and use that value in the passthru call (keep the existing passthru,
escapeshellarg and dirname usage but resolve vendor/bin/stree relative to the
script).
demos/medical-triage/src/Becoming/DevBecoming.php (1)

22-47: Consider extracting shared DevBecoming logic to reduce per-demo duplication.

This class is nearly identical across hello-world, medical-triage, order-processing, and user-registration — only the output filename differs. Since each demo has its own src/ tree and composer.json, full deduplication may be out of scope, but you could at least parameterize the log filename (e.g., pass it via a #[Named] string binding in DevModule) so the class bodies become trivially mergeable later, or ship a single shared helper. Optional — purely a maintainability nit for dev-only code.

Also, two minor robustness notes for the finally block:

  • json_encode(...) can return false (e.g., on malformed UTF-8 or a circular structure thrown from flush()); file_put_contents will then silently write an empty file, masking the real problem. Adding JSON_THROW_ON_ERROR would surface it.
  • mkdir(...) return value is ignored; if creation fails due to a race or permissions, the subsequent write fails silently.
♻️ Suggested tightening
-            $dir = dirname(__DIR__, 2) . '/var/log';
-            if (! is_dir($dir)) {
-                mkdir($dir, 0755, true);
-            }
-
-            file_put_contents(
-                $dir . '/medical-triage.json',
-                json_encode($this->logger->flush(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
-            );
+            $dir = dirname(__DIR__, 2) . '/var/log';
+            if (! is_dir($dir) && ! mkdir($dir, 0755, true) && ! is_dir($dir)) {
+                return;
+            }
+
+            file_put_contents(
+                $dir . '/medical-triage.json',
+                json_encode(
+                    $this->logger->flush(),
+                    JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,
+                ),
+            );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@demos/medical-triage/src/Becoming/DevBecoming.php` around lines 22 - 47,
DevBecoming's finally block should be made robust and the filename
parameterized: change DevBecoming to accept a filename (e.g., via the
constructor/#[Named] binding) instead of hardcoding 'medical-triage.json', and
update __invoke to use that injected filename; in the finally block, call
json_encode/flush with JSON_THROW_ON_ERROR to surface encoding errors (catching
and logging if needed), ensure mkdir succeeded (or re-check is_dir and log/throw
if creation failed) before writing, and verify file_put_contents returned a
non-false result (log/throw on failure) after calling $this->logger->flush() so
write errors aren’t silently ignored.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@demos/order-processing/var/log/order-processing.json`:
- Line 53: Replace the real-looking test PAN used in the JSON transcript by
changing the "cardNumber" value (currently "4111111111111111") to an
obviously-fake or masked string like "************1111" or "<redacted>" so
secret scanners won’t flag the committed sample while keeping the transcript
readable.

In `@demos/user-registration/var/log/user-registration.json`:
- Around line 94-98: The sample transcript contains deterministic-looking
credentials (welcomeToken, hashedPassword, avatarUrl derived from email) that
trigger secret scanners; update the fixture output in user-registration.json to
use obviously-scrubbed placeholders (e.g., set welcomeToken to "<generated>",
hashedPassword to "<bcrypt>", avatarUrl to "<avatar>") or otherwise redact the
values so the JSON still shows the shape but no longer looks like real secrets,
ensuring any code that reads these fixtures handles the placeholder format where
relevant (search for uses of welcomeToken, hashedPassword, avatarUrl in relevant
test/fixture loaders and adjust expectations if needed).

---

Nitpick comments:
In `@demos/medical-triage/bin/be.php`:
- Around line 22-27: Add an instanceof assertion to verify the pipeline output
($final) matches the expected final class before using it: locate the code that
calls $becoming(new PatientInput(...)) and immediately after the result is
produced (before or after the printf) add an assertion like assert($final
instanceof <ExpectedFinalClass>) — replace <ExpectedFinalClass> with the actual
final type returned by the triage pipeline (e.g., TriageResult) to match the
other demos' pattern and document the expected outcome.

In `@demos/medical-triage/src/Becoming/DevBecoming.php`:
- Around line 22-47: DevBecoming's finally block should be made robust and the
filename parameterized: change DevBecoming to accept a filename (e.g., via the
constructor/#[Named] binding) instead of hardcoding 'medical-triage.json', and
update __invoke to use that injected filename; in the finally block, call
json_encode/flush with JSON_THROW_ON_ERROR to surface encoding errors (catching
and logging if needed), ensure mkdir succeeded (or re-check is_dir and log/throw
if creation failed) before writing, and verify file_put_contents returned a
non-false result (log/throw on failure) after calling $this->logger->flush() so
write errors aren’t silently ignored.

In `@demos/user-registration/bin/be.php`:
- Line 33: The passthru call uses a relative 'vendor/bin/stree' which breaks
when the script is run from a different CWD; change the command to build the
binary path relative to the script directory (use dirname(__DIR__, 3) to reach
the repo root from demos/user-registration/bin), e.g. compute the full path to
vendor/bin/stree via dirname(__DIR__, 3) . '/vendor/bin/stree', wrap it with
escapeshellarg as before, and use that value in the passthru call (keep the
existing passthru, escapeshellarg and dirname usage but resolve vendor/bin/stree
relative to the script).

In `@demos/user-registration/src/Becoming/DevBecoming.php`:
- Around line 30-46: The finally block in DevBecoming::__invoke currently writes
logs and can throw, which would mask exceptions from ($this->becoming)($input);
wrap the entire persistence sequence (the dirname/ mkdir check, json_encode of
$this->logger->flush(), and file_put_contents) in its own try/catch inside the
finally so any errors are caught and do not propagate; on catch write a concise
error to STDERR (e.g., via fwrite(STDERR, ...)) and do not rethrow; additionally
validate json_encode succeeded (or use JSON_THROW_ON_ERROR inside that try)
before calling file_put_contents to avoid silent false results from
$this->logger->flush().
- Around line 22-47: DevBecoming's __invoke finally block is duplicated across
demos with only the output filename differing (e.g., user-registration.json vs
hello-world.json); when you fix the finally behavior (e.g., ensure
logger->flush() errors are handled, directory creation permissions, or atomic
file write), apply the same change to the other DevBecoming classes so all demos
stay consistent—locate the DevBecoming class and its __invoke method and update
the file write logic (logger->flush(), dirname(...)/var/log creation, and
file_put_contents call) and replicate the identical fix to the other three
DevBecoming files, preserving each demo's distinct JSON filename.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3cca40b2-6691-41ff-a0c1-a9277aa45456

📥 Commits

Reviewing files that changed from the base of the PR and between ff9a858 and c640481.

📒 Files selected for processing (22)
  • demos/hello-world/bin/be.php
  • demos/hello-world/src/Becoming/DevBecoming.php
  • demos/hello-world/src/Module/AppModule.php
  • demos/hello-world/src/Module/DevModule.php
  • demos/hello-world/src/Module/DevSemanticLoggerProvider.php
  • demos/hello-world/var/log/hello-world.json
  • demos/medical-triage/bin/be.php
  • demos/medical-triage/src/Becoming/DevBecoming.php
  • demos/medical-triage/src/Module/DevModule.php
  • demos/medical-triage/src/Module/DevSemanticLoggerProvider.php
  • demos/medical-triage/var/log/medical-triage.json
  • demos/order-processing/bin/be.php
  • demos/order-processing/src/Becoming/DevBecoming.php
  • demos/order-processing/src/Module/DevModule.php
  • demos/order-processing/src/Module/DevSemanticLoggerProvider.php
  • demos/order-processing/var/log/order-processing.json
  • demos/user-registration/bin/be.php
  • demos/user-registration/src/Becoming/DevBecoming.php
  • demos/user-registration/src/Module/AppModule.php
  • demos/user-registration/src/Module/DevModule.php
  • demos/user-registration/src/Module/DevSemanticLoggerProvider.php
  • demos/user-registration/var/log/user-registration.json

Comment thread demos/order-processing/var/log/order-processing.json
Comment thread demos/user-registration/var/log/user-registration.json Outdated
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@koriym
koriym merged commit 3fb553a into 1.x Apr 20, 2026
25 checks passed
@koriym
koriym deleted the demos-dev-module branch April 20, 2026 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant